package com.rambo.dsd.base.dao.impl;

import com.rambo.dsd.base.dao.inter.BaseDao;
import com.rambo.tools.CollectionUtil;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * Description: dao 底层基类(勿动)
 */
@SuppressWarnings("unchecked")
public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

    private Class<T> poClass;

    private SessionFactory sessionFactory;

    public BaseDaoImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
        this.poClass = null;
        Class<?> c = getClass();
        Type type = c.getGenericSuperclass(); //反射获取超类
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.poClass = (Class<T>) parameterizedType[0];
        }
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    /**
     * 根据ID获取实体对象.
     *
     * @param id 记录ID
     * @return 实体对象
     */
    @Override
    @Transactional(readOnly = true)
    public T getByKey(PK id) {
        Assert.notNull(id, "id is required");
        T t = (T) getSession().get(poClass, id);
        try {
            return t == null ? poClass.getConstructor().newInstance() : t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存实体对象.
     *
     * @param entity 对象
     * @return ID
     */
    @Override
    @Transactional
    public T add(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().save(entity);
        return entity;
    }

    /**
     * 更新实体对象
     *
     * @param entity 对象
     * @return 更新的对象
     */
    @Override
    @Transactional
    public T edit(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().update(entity);
        return entity;
    }

    /**
     * 根据 ID 删除实体
     *
     * @param id 主键
     * @return 更新的对象
     */
    @Override
    @Transactional
    public T deleteByKey(PK id) {
        Assert.notNull(id, "id is required");
        T t = (T) getSession().load(poClass, id);
        getSession().delete(t);
        return t;
    }

    /**
     * 通过实体类样本，获取实体列表
     *
     * @param entity 实体类样本
     * @return 排序相同实体列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> findByExample(T entity) {
        Criteria criteria = getSession().createCriteria(entity.getClass());
        criteria.add(Example.create(entity));
        return criteria.list();
    }


    /**
     * 通过实体类样本，获取排序相同实体列表
     *
     * @param entity 实体类样本
     * @param order  排序对象
     * @return 排序相同实体列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> findByExample(T entity, Order order) {
        Criteria criteria = getSession().createCriteria(entity.getClass());
        if (order != null) {
            criteria.addOrder(order);
        }
        return criteria.add(Example.create(entity)).list();
    }


    /**
     * 通过实体类样本，获取实体列表中的第一个
     *
     * @param entity 样例实体
     * @return 对应应样例实体
     */
    @Override
    @Transactional(readOnly = true)
    public T getOneByExample(T entity) {
        List<T> list = findByExample(entity);
        if (!CollectionUtil.isEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 通过实体类样本，排序后获取实体列表中的第一个
     *
     * @param entity 样例实体
     * @param order  排序对象
     * @return 对应样例实体
     */
    @Override
    @Transactional(readOnly = true)
    public T getOneByExample(T entity, Order order) {
        Criteria criteria = getSession().createCriteria(entity.getClass());
        criteria.add(Example.create(entity));
        if (order != null) {
            criteria.addOrder(order);
        }
        List list = criteria.list();
        if (!CollectionUtil.isEmpty(list)) {
            list.get(0);
        }
        return null;
    }
}
